Go 1.17.6 发布关键词:iOS、macOS、HTTP2
2021年12月09日发布了安全更新 Go 1.17.5 和 Go 1.16.12, 包括 syscall 和 net/http 包的安全修复。
Severe HTTP/2 server Denial of Service (CVE-2021-44716)
今天(2022年01月07日) Go 又发布了 Go 1.17.6 和 Go 1.16.13。
本次更新包括哪些更新?
以下我们来看看详细分析:
runtime: mallocs cause "base outside usable address space" panic when running on iOS 14 [1.17 backport] #48116
运行报错信息:
runtime: memory allocated by OS [0x2ac000000, 0x2b0000000) not in usable address space: base outside usable address space
fatal error: memory reservation exceeds address space limit
作者在 CL 修复中的描述:
在 iOS<14,地址空间被严格限制在 8 GiB,或 33 位。因此,页面分配程序还假定所有堆内存都位于该区域。这是特别必要的,因为页面分配器有一个与可用地址空间大小成比例的 PROT_NONE 映射,所以这使映射非常小。
但是从 iOS 14 开始,这个限制就放宽了,mmap 可以开始返回 <14 范围之外的地址。在现在这意味着在 iOS 14 和之后的版本中,当一个堆区域被映射到旧范围之外时,用户会在页面分配程序中遇到一个错误。
这个变化增加了 ios/arm64 的 heapAddrBits 到 40,同时使 ios/arm64 使用 64 位的 pagealloc 实现(保留和增量映射),以适应 iOS <14 和 14+。
一旦 iOS <14 被弃用,我们就可以移除这些异常,并像对待其他 arm64 平台一样对待 iOS /arm64。
在这里,这个更改还使 BaseChunkIdx 表达式更易于阅读。
var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*sys.GoosAix))
优化为:
var BaseChunkIdx = func() ChunkIdx {
var prefix uintptr
if pageAlloc64Bit != 0 {
prefix = 0xc000
} else {
prefix = 0x100
}
baseAddr := prefix * pallocChunkBytes
if sys.GoosAix != 0 {
baseAddr += arenaBaseOffset
}
return ChunkIdx(chunkIndex(baseAddr))
}()
具体 CL 369737[1]
runtime: race detector SIGABRT or SIGSEGV on macOS Monterey [1.17 backport] #50073
在 macOS 12 上,默认使用了一个新的 malloc 实现(nano),显然它保留了 0x600000000000-0x600020000000 的地址范围,这与 TSAN 用于 Go 的地址范围冲突。通过稍微改变地址范围来解决这个问题。
CL 370697[2]
x/net/http2: http.Server.WriteTimeout does not fire if the http2 stream's window is out of space. [1.17 backport] #49921
http2 随机写调度程序不应键入 rst_stream 帧与数据帧,而是将它们视为控制帧。如果数据帧阻止队列,则可能存在死锁情况,因为如果发件人想要关闭它,它会发送 rst 帧,但如果客户端没有排出队列,则会卡住并且发件人无法完成。
@davecheney[4]给的例子:
package main
import (
"io"
"log"
"net/http"
"net/http/httptest"
"strings"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
data := strings.Repeat("x", 1<<16)
tick := time.NewTicker(100 * time.Millisecond) // 如果把 100 改为 1,则不会出现:`2022/01/07 10:04:54 wrote 0, err http2: stream closed`
defer tick.Stop()
for {
select {
case <-tick.C:
n, err := io.WriteString(w, data)
log.Printf("wrote %d, err %v", n, err)
if err != nil {
return
}
case <-r.Context().Done():
log.Printf("context cancelled")
return
}
}
}
func main() {
sv := httptest.NewUnstartedServer(http.HandlerFunc(handler))
sv.EnableHTTP2 = true
sv.Config.WriteTimeout = 1 * time.Second
sv.StartTLS()
resp, err := sv.Client().Get(sv.URL + "/")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
select {} // block forever
}
CL 375719[3]
不知道大家在使用 http2 的包有没有遇到这个问题呢?如果有,那你应该要感谢 @davecheney[4] ,因为 Go 团队有人提议将其放在 Go 1.18.1 来发布哦,是 @davecheney[4] 将其争取到 Go 1.17.6 就发布了。
其他内容,大家可以前往 Go 1.17.6 发布 notes[5] 中查阅。
CL 369737: https://go-review.googlesource.com/c/go/+/369737/
[2]CL 370697: https://go-review.googlesource.com/c/go/+/370697/
[3]CL 375719: https://go-review.googlesource.com/c/net/+/375719/
[4]@davecheney: https://github.com/davecheney
[5]Go 1.17.6 发布 notes: https://github.com/golang/go/issues?q=milestone%3AGo1.17.6+label%3ACherryPickApproved
往期更新
[Security] Go 1.17.1 and 1.16.8 are released!
[Security] Go 1.17.2 and 1.16.9 are released!